package ewu

import ewu._
import ewu.expressions._
import java.util.ArrayList
import scala.collection.mutable.ArrayBuffer

/**
 * Diese Klasse stellt die Oberklasse fuer alle boolschen Ausdruecke
 * dar. Zusaetzlich werden hier Funktionen zum Reduzieren von Ausdruecken
 * definiert.
 */

trait BoolExpression {
  
  def evaluate (env: Environment): Option[Boolean]
  
  override def toString: String
  
  def reduce: BoolExpression
  
  def tab (t: Int): String = {
    if (t > 0)
      " " + tab(t-1)
    else
      ""
  }
    
  def getVariables(a: ArrayBuffer[Name])
  
  def replaceVariable(fromVar: Name, toVar: Expression) = and_rek(this, fromVar, toVar)

  def and_rek (expr: BoolExpression, var_name: Name, reg_rep: Expression) : BoolExpression = {
    expr match {
      case Not (expr: BoolExpression) =>
        Not(and_rek(expr, var_name, reg_rep))
      case AND (left: BoolExpression, right: BoolExpression) =>
        AND(and_rek(left, var_name, reg_rep), 
          and_rek(right, var_name, reg_rep))
      case OR (left: BoolExpression, right: BoolExpression) =>
        OR(and_rek(left, var_name, reg_rep), 
          and_rek(right, var_name, reg_rep))
      case Equal (left: Expression, right: Expression) =>
        Equal(exp_rek(left, var_name, reg_rep).reduce, 
          exp_rek(right, var_name, reg_rep).reduce)
      case Unequal (left: Expression, right: Expression) =>
        Unequal(exp_rek(left, var_name, reg_rep).reduce, 
          exp_rek(right, var_name, reg_rep).reduce)
      case Lesser (left: Expression, right: Expression) =>
        Lesser(exp_rek(left, var_name, reg_rep).reduce, 
          exp_rek(right, var_name, reg_rep).reduce)
      case LOE (left: Expression, right: Expression) =>
        LOE(exp_rek(left, var_name, reg_rep).reduce, 
          exp_rek(right, var_name, reg_rep).reduce)
      case Greater(left: Expression, right: Expression) =>
        Greater(exp_rek(left, var_name, reg_rep).reduce, 
          exp_rek(right, var_name, reg_rep).reduce)
      case GOE (left: Expression, right: Expression) =>
        GOE (exp_rek(left, var_name, reg_rep).reduce, 
          exp_rek(right, var_name, reg_rep).reduce)
       case ExistsQuantor(variable: String, range: ValueRange, booli: BoolExpression) =>
        range match {
          case ValueRange(from: BigInt, to: BigInt, fromE: Expression, toE: Expression) =>
            return ExistsQuantor(variable, new ValueRange(exp_rek(fromE, var_name, reg_rep).reduce,exp_rek(toE, var_name, reg_rep).reduce), and_rek(booli, var_name, reg_rep))
          case _ =>
            return ExistsQuantor(variable, range, and_rek(booli, var_name, reg_rep))
        }
      case AllQuantor(variable: String, range: ValueRange, booli: BoolExpression) =>
        range match {
          case ValueRange(from: BigInt, to: BigInt, fromE: Expression, toE: Expression) =>
            return AllQuantor(variable, new ValueRange(exp_rek(fromE, var_name, reg_rep).reduce,exp_rek(toE, var_name, reg_rep).reduce), and_rek(booli, var_name, reg_rep))
          case _ =>
            return AllQuantor(variable, range, and_rek(booli, var_name, reg_rep))
        }
      case _ =>
        new True()
    }
  }

  def exp_rek (expr: Expression, var_name: Name, reg_rep: Expression) : Expression = {
     expr match {
        case Name (name: String) =>
          if(name.equals(var_name.toString))
            reg_rep
          else
            expr
        case Plus(left: Expression, right: Expression) =>
          Plus(exp_rek(left, var_name, reg_rep).reduce, 
            exp_rek(right, var_name, reg_rep).reduce)
        case Minus(left: Expression, right: Expression) =>
          Minus(exp_rek(left, var_name, reg_rep).reduce,
            exp_rek(right, var_name, reg_rep).reduce)
        case Mult(left: Expression, right: Expression) =>
          Mult(exp_rek(left, var_name, reg_rep).reduce,
            exp_rek(right, var_name, reg_rep).reduce)
        case Div(left: Expression, right: Expression) =>
          Div(exp_rek(left, var_name, reg_rep).reduce,
            exp_rek(right, var_name, reg_rep).reduce)
        case Modulo(left: Expression, right: Expression) =>
          Modulo(exp_rek(left, var_name, reg_rep).reduce,
            exp_rek(right, var_name, reg_rep).reduce)
        case PowerOf(left: Expression, right: Expression) =>
          PowerOf(exp_rek(left, var_name, reg_rep).reduce,
            exp_rek(right, var_name, reg_rep).reduce)
        case functionExpression(name:String,  
                                params:Array[Expression]) =>
          functionExpression(name,
            func_rep(params, var_name, reg_rep))
        case _ =>  expr
    }
  }

  def func_rep(params:Array[Expression], var_name: Name, reg_rep: Expression):
                                                                       Array[Expression] = {
    var tmpA:Array[Expression] = params.clone
    for(i <- 0 until params.length) {
      tmpA(i) = exp_rek(params(i), var_name, reg_rep)
    }
    tmpA
  }

  def isTrue: Boolean
  
  def replaceQuantor(addfuncs: ArrayList[String], arrayvars: ArrayList[String]): BoolExpression = {return this}
  
}


 